/*
  AA Trees
  (C) 2006 Haibo Hu<hhb3974@sohu.com>
  
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include <rbtree.h>


static struct rb_node *__skew(struct rb_node *node, struct rb_root *root)
{		if(node->rb_left&&node->level==node->rb_left->level)
		{
		struct rb_node *left = node->rb_left;

		if ((node->rb_left = left->rb_right))
			left->rb_right->rb_parent = node;
		left->rb_right = node;

		if ((left->rb_parent = node->rb_parent))
		{
			if (node == node->rb_parent->rb_right)
				node->rb_parent->rb_right = left;
			else
				node->rb_parent->rb_left = left;
		}
		else
			root->rb_node = left;
		node->rb_parent = left;
		node=left;
		}
		return node;
}

static struct rb_node *__split(struct rb_node *node, struct rb_root *root)
{		if(node->rb_right&&node->rb_right->rb_right&&node->level==node->rb_right->rb_right->level)
		{
		struct rb_node *right = node->rb_right;

		if ((node->rb_right = right->rb_left))
			right->rb_left->rb_parent = node;
		right->rb_left = node;

		if ((right->rb_parent = node->rb_parent))
		{
			if (node == node->rb_parent->rb_left)
				node->rb_parent->rb_left = right;
			else
				node->rb_parent->rb_right = right;
		}
		else
			root->rb_node = right;
		node->rb_parent = right;
		right->level++;
		node=right;
		}
		return node;
}


void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
	struct rb_node *parent=node->rb_parent;
	int level=0;

	while (parent)
	{	level=parent->level;
		parent=__skew(parent,root);
		parent=__split(parent,root);
		if((level==parent->level)&&((!parent->rb_parent)||(parent->rb_parent->level!=parent->rb_right->level)))
			break;
		parent=parent->rb_parent;
	}
}


void rb_erase(struct rb_node *node, struct rb_root *root)
{
	struct rb_node *parent,*child;

	if(!node->rb_right)
	{
		parent = node->rb_parent;

		if (parent)
		{
			if (parent->rb_left == node)
				parent->rb_left = 0;
			else
				parent->rb_right = 0;
		}
		else
			root->rb_node = 0;
		child=0;
	}
	else
	{
		struct rb_node *old = node, *left;

		node = node->rb_right;
		while ((left = node->rb_left))
			node = left;
		child = node->rb_right;
		parent = node->rb_parent;

		if (child)
			child->rb_parent = parent;
		if (parent)
		{
			if (parent->rb_left == node)
				parent->rb_left = child;
			else
				parent->rb_right = child;
		}
		else
			root->rb_node = child;

		if (node->rb_parent == old)
			parent = node;
		node->rb_parent = old->rb_parent;
		node->level = old->level;
		node->rb_right = old->rb_right;
		node->rb_left = old->rb_left;

		if (old->rb_parent)
		{
			if (old->rb_parent->rb_left == old)
				old->rb_parent->rb_left = node;
			else
				old->rb_parent->rb_right = node;
		} else
			root->rb_node = node;

		if(old->rb_left)
			old->rb_left->rb_parent = node;
		if (old->rb_right)
			old->rb_right->rb_parent = node;
	}

	if(!parent)
		return;
		
	if((!parent->rb_left&&parent->level==2)||(!parent->rb_right&&parent->level==2))
	{	parent->level--;
		if(parent->rb_right&&parent->level < parent->rb_right->level)
			parent->rb_right->level=parent->level;
		parent=__skew(parent,root);
		if(parent->rb_right)
			parent->rb_right=__skew(parent->rb_right,root);
		if(parent->rb_right&&parent->rb_right->rb_right)
			parent->rb_right->rb_right=__skew(parent->rb_right->rb_right,root);
		parent=__split(parent,root);
		if(parent->rb_right)
			parent->rb_right=__split(parent->rb_right,root);
		if(!(parent=parent->rb_parent))
			return;
	}

	while((parent->rb_left&&parent->rb_left->level < parent->level-1)||(parent->rb_right&&parent->rb_right->level < parent->level-1))
	{	parent->level--;
		if(parent->level < parent->rb_right->level)
			parent->rb_right->level=parent->level;
		parent=__skew(parent,root);
		parent->rb_right=__skew(parent->rb_right,root);
		parent->rb_right->rb_right=__skew(parent->rb_right->rb_right,root);
		parent=__split(parent,root);
		parent->rb_right=__split(parent->rb_right,root);
		if(!(parent=parent->rb_parent))
			break;
	}	
}

/*
 * This function returns the first node (in sort order) of the tree.
 */
struct rb_node *rb_first(struct rb_root *root)
{
	struct rb_node	*n;

	n = root->rb_node;
	if (!n)
		return 0;
	while (n->rb_left)
		n = n->rb_left;
	return n;
}

struct rb_node *rb_next(struct rb_node *node)
{
	/* If we have a right-hand child, go down and then left as far
	   as we can. */
	if (node->rb_right) {
		node = node->rb_right; 
		while (node->rb_left)
			node=node->rb_left;
		return node;
	}

	/* No right-hand children.  Everything down and left is
	   smaller than us, so any 'next' node must be in the general
	   direction of our parent. Go up the tree; any time the
	   ancestor is a right-hand child of its parent, keep going
	   up. First time it's a left-hand child of its parent, said
	   parent is our 'next' node. */
	while (node->rb_parent && node == node->rb_parent->rb_right)
		node = node->rb_parent;

	return node->rb_parent;
}

struct rb_node *rb_prev(struct rb_node *node)
{
	/* If we have a left-hand child, go down and then right as far
	   as we can. */
	if (node->rb_left) {
		node = node->rb_left; 
		while (node->rb_right)
			node=node->rb_right;
		return node;
	}

	/* No left-hand children. Go up till we find an ancestor which
	   is a right-hand child of its parent */
	while (node->rb_parent && node == node->rb_parent->rb_left)
		node = node->rb_parent;

	return node->rb_parent;
}

void rb_replace_node(struct rb_node *victim, struct rb_node *new,
		     struct rb_root *root)
{
	struct rb_node *parent = victim->rb_parent;

	/* Set the surrounding nodes to point to the replacement */
	if (parent) {
		if (victim == parent->rb_left)
			parent->rb_left = new;
		else
			parent->rb_right = new;
	} else {
		root->rb_node = new;
	}
	if (victim->rb_left)
		victim->rb_left->rb_parent = new;
	if (victim->rb_right)
		victim->rb_right->rb_parent = new;

	/* Copy the pointers/colour from the victim to the replacement */
	*new = *victim;
}
